package com.example.java_gobang.game;

import com.example.java_gobang.model.MatchResponse;
import com.example.java_gobang.model.Room;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

//这个类表示"匹配器",通过这个类负责完成整个匹配功能
@Component
public class Matcher {
    //创建三个匹配队列
    private Queue<User>normalQueue=new LinkedList<>();
    private Queue<User>higQueue=new LinkedList<>();
    private Queue<User>veryHighQueue=new LinkedList<>();

    @Autowired
    private OnlineUserManager onlineUserManager;


    private ObjectMapper objectMapper=new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    //操作匹配队列的方法
    //把玩家放到匹配队列中
    public void add(User user){
        if(user.getScore()<2000){
            synchronized (normalQueue){
                normalQueue.offer(user);
                normalQueue.notify();
            }
            System.out.println("把玩家 "+user.getUsername()+"加入到了normalQueue中");
        } else if(user.getScore()>=2000&&user.getScore()<3000){
            synchronized (higQueue){
                higQueue.offer(user);
                higQueue.notify();
            }
            System.out.println("把玩家 "+user.getUsername()+"加入到了higQueue中");
        }else{
            synchronized (veryHighQueue){
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }
            System.out.println("把玩家 "+user.getUsername()+"加入到了veryHighQueue中");
        }
    }

    //取消匹配(当玩家点击匹配的时候,就需要把玩家从匹配队列中删除)
    public void remove(User user){
        if(user.getScore()<2000){
            synchronized (normalQueue){
                normalQueue.remove(user);

            }
            System.out.println("把玩家 "+user.getUsername()+"移除了了normalQueue中");
        }else if(user.getScore()>=2000&&user.getScore()<3000){
            synchronized (higQueue){
                higQueue.remove(user);

            }
            System.out.println("把玩家 "+user.getUsername()+"移除了higQueue中");
        }else{
            synchronized (veryHighQueue){
                veryHighQueue.remove(user);

            }
            System.out.println("把玩家 "+user.getUsername()+"移除了veryHighQueue中");
        }
    }


    public Matcher(){
        //创建三个线程,分别针对三个匹配队列进行操作
        Thread t1=new Thread(){
            @Override
            public void run() {
                //扫描normalQueue
                while(true){
                    handlerMatch(normalQueue);
                }
            }
        };
        t1.start();
        Thread t2=new Thread(){
            @Override
            public void run() {
                while(true){
                    handlerMatch(higQueue);
                }
            }
        };
        t2.start();
        Thread t3=new Thread(){
            @Override
            public void run() {
                while (true){
                    handlerMatch(veryHighQueue);
                }
            }
        };
        t3.start();
    }

    //进行匹配
    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue){
            try {
                //1.检测队列中元素个数是否达到2,没有到达2就无法匹配,等待下次扫描
                //队列的初始情况可能是空,如果往队列中添加的1个元素,仍然可以进行后续的匹配操作
                //因此这里使用while循环检查是更合理的
                while(matchQueue.size()<2){
                    matchQueue.wait();
                }

                //2. 尝试从队列中取出两个玩家
                User player1=matchQueue.poll();
                User player2=matchQueue.poll();
                System.out.println("匹配出两个玩家: "+player1.getUsername()+","+player2.getUsername());

                //3. 获取到玩家的websocket的会话
                //获取会话的目的是为了告诉玩家,你排到了(检测是否在连接之前关闭页面)
                WebSocketSession session1= onlineUserManager.getFromGameHall(player1.getUserId());
                WebSocketSession session2= onlineUserManager.getFromGameHall(player2.getUserId());
                //理论上来说,匹配队列的玩家一定是在线的状态
                //因为前面的逻辑里进行了处理,当玩家断开连接的时候就把玩家从匹配队列移除了
                //但此处仍然进行一次判定(双重判定)
                if(session1==null){
                    //如果玩家1现在不在线了,就把玩家2重新放到匹配队列中
                    matchQueue.offer(player2);
                    return;
                }
                if(session2==null){
                    //如果玩家2现在不在线了,就把玩家1重新放到匹配队列中
                    matchQueue.offer(player1);
                    return;
                }
                //匹配到同一个用户,理论上已经之前处理了(玩家下线就移除队列和禁止玩家多开)
                //双重判定(更好的稳定性 )以免前面的逻辑出现bug带来严重的后果
                if(session1==session2){
                    //把其中一个玩家放回到匹配队列中
                    matchQueue.offer(player1);
                    return;
                }

                //4.把这两个玩家放都一个房间中
                Room room=new Room();
                roomManager.add(room,player1.getUserId(),player2.getUserId());


                //5 给玩家反馈信息,你匹配到对手了
                //通过websocket 返回一个message为'matchSuccess'这样的响应
                //此处要给两个玩家返回"匹配成功",因此要返回两次
                MatchResponse response1=new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                //
                String json1= objectMapper.writeValueAsString(response1);
                session1.sendMessage(new TextMessage(json1));

                MatchResponse response2=new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                //把json2对象转成json字符串
                String json2= objectMapper.writeValueAsString(response2);
                session2.sendMessage(new TextMessage(json2));
            }catch (IOException e){
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
